//
//  ST_TIANEngagementManager.swift
//  btvideo
//
//  Created by Jason on 2021/7/29.
//  Copyright © 2021 JarvanZhang. All rights reserved.
//

import UIKit
import RealmSwift
import NIMSDK
import SwiftyJSON
import SwiftyUserDefaults
import RxCocoa
import RxSwift
import NERtcSDK

enum TIANEngagementChannelStatus {
    case prepare
    case entered
    case left
}

/// 云信SDK 交互
class ST_TIANEngagementManager: NSObject {
    
    static let defaultManager = ST_TIANEngagementManager()
    // Can't init is singleton
    private override init() {
        super.init()
        
        setup_notifications()
    }
    
    fileprivate weak var delegate:ST_TIANEngagementLayoutUIProtocol?
    
    // MARK: - Properties
    
    /// 小窗模式
    var isSuspended = false
    
    fileprivate var receiveFirstFrame = false
    
    weak var coinAlert :BTVerticalAlertViewController?
    
    var displayIncomeControl:Bool{
        if ST_BTUserInfoManager.shared.current_account_info?.userinfo?.sex == .male{
            return false
        }else{
            return true
        }
    }
    
    fileprivate(set) var engagement_entiy:ST_TIANEngagementEntiy?
    
    
    fileprivate(set) var agoraKit = NERtcEngine.shared()

    /// 自己是否在频道
    private(set) var channelStatusBehavior:BehaviorRelay = BehaviorRelay<TIANEngagementChannelStatus>.init(value: .prepare)
    
    
#if DEBUG
    private let waitTimeoutSeconds = 60
#else
    private let waitTimeoutSeconds = 2*60
#endif
    
    private let remainderToastSeconds = 30
    
    private var timerDisposable:Disposable?
    
    private var detectTimeoutDisposable:Disposable?
    
    private(set) var remoteUserId:UInt64?
    /// 对面静音的时间(静音时间过长，挂断)
    private var muteRaw = [UInt64:UInt64]()
    
    /// 被静音等待最长时间（超时挂断）
    private var muteWaitingTime:Int = 10
    
    weak var bigVideoViews:UIView?
    
    weak var smallVideoViews:UIView?
    
    /// 状态 talking ， hangup
    fileprivate var currentEngagementStatus = ST_EngagementStatus.normal{
        didSet{
            
            if let last = lastEngagementStatus,last == currentEngagementStatus{
                return
            }
            
            update_engagement_status_event_handle()
            
            lastEngagementStatus = currentEngagementStatus
            
        }
    }
    
    fileprivate var lastEngagementStatus:ST_EngagementStatus?
    
    
    
    fileprivate lazy var realm:Realm = {
        return try! Realm()
    }()
    
    /// 扣费
    fileprivate var engagementLog:ST_EngagementCentLog?
    
    fileprivate var timer:Timer?
    
    /// 状态变更
    fileprivate func update_engagement_status_event_handle(){
        
        
        guard let entity = engagement_entiy else { return }
        
        delegate?.engagementStateUpdate(state: currentEngagementStatus)
        
        switch currentEngagementStatus {
            
        case .talking:
            
            engagementLog = nil
            
            /// 对方也加入频道，取消延时任务
//            NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(WaitingTimeoutAction), object: nil)
            
            ST_MediaChatDispatcher.shared.talk_p2_p(sessionId: entity.sessionId)
            
            receiveFirstFrame = true
            
            ST_MediaChatDispatcher.shared.stop_waiting_voice()
            
            print("【先后顺序问题】--聊上了",Date())
            
            startTimer()
            
            if entity.impressionSeconds > 0 &&  Defaults[.isPanda] == false && displayIncomeControl == false{
                
                
                delegate?.engagementMyCurrentImpression(currentSeconds: entity.impressionSeconds, haveState: entity.haveImpression)
                
            }
            
            push_talking_log()
            
        case .hungUp:
            
            push_talking_log(end: true)
            
            ST_MediaChatDispatcher.shared.append_call_history(targetAccid: entity.sessionId, type: entity.chatType == .voice ? 1 : 2, duration: entity.totalSeconds)
            
            ST_EngagementCentServer.shared.push_log()
            
//            pushLeaveShumeiHandle()
            
            pushLogAction()
            
            ST_MediaChatDispatcher.shared.hung_up_p2_p(sessionId: entity.sessionId)
            
            send_hung_up_chat_history()
            
            destroyTimer()
            
            if isSuspended {
                ST_SwiftyFloatingWidget.provider.destroy()
            }
            
            ST_LiveBeautyWidget.shared.cancel_match_game()
            
            destroy()
            
            
            isSuspended = false
            
        default:
            break
        }
        
    }
    
}



extension ST_TIANEngagementManager{
    
    fileprivate func initializeAgoraEngine() {
        // Initializes the Agora engine with your app ID.
        
        let context = NERtcEngineContext()
        context.engineDelegate = self
        context.appKey = PH.nimAppID
        //默认情况下日志会存储在App沙盒的Documents目录下
        let logSetting = NERtcLogSetting()
#if DEBUG
        logSetting.logLevel = .info
#else
        logSetting.logLevel = .warning
#endif
        context.logSetting = logSetting
        
        
        self.agoraKit.setupEngine(with: context)
        
        self.agoraKit.enableAudioVolumeIndication(true, interval: 1000)
        
    }
    
    fileprivate func setupAgoraVoice(){
        agoraKit.setAudioProfile(.standard, scenario: .speech)
        agoraKit.enableLocalAudio(true)
    }
    
    fileprivate func setupAgoraVideo(){
        
        
        //初始化美颜模块
        //开启美颜功能
        NEBeautyManager.shared().initNEBeauty()
        NEBeautyManager.shared().enableNEBeauty(true)
        
        
        agoraKit.setAudioProfile(.standard, scenario: .speech)
        let configuration = NERtcVideoEncodeConfiguration()
        configuration.width = 1280
        configuration.height = 720
        configuration.frameRate = .fps15
        agoraKit.setLocalVideoConfig(configuration)
        agoraKit.enableLocalAudio(true)
        agoraKit.enableLocalVideo(true)
        
        let userModel = NTESDemoUserModel()
        
        userModel.renderContainer = bigVideoViews
        
        NERtcEngine.shared().setupLocalVideoCanvas(userModel.setupCanvas())
        
        
        
    }
    
    fileprivate func joinChannel() {
        
        guard let entity = engagement_entiy else { return }
        
        print("[strange bug] -- 将要加入的 频道：",entity.channelId ," token:",entity.channelToken,"--myUid",entity.currentId)
        
//        engagement_entiy.myRtcId
        
        let resultCode = agoraKit.joinChannel(withToken: entity.channelToken, channelName: entity.channelId, myUid: UInt64(entity.currentId)) {[weak self] error, channelId, elapesd, uid in
            
            if let e = error{
                
                self?.delegate?.engagementAlert(text: "加入频道失败,请稍后再试")
                
                print("#98013 join error:",e)
                
                self?.channelStatusBehavior.accept(.left)
            }else{
                
                print("#98013 didJoinChannel uid:",uid,"--",Date())
               
                self?.channelStatusBehavior.accept(.entered)
//                self?.appendChannel(id: Int(uid))
                UIApplication.shared.isIdleTimerDisabled = true
                
                self?.detectWaitTimeout()
                
            }
            
        }
        
        print("#98013 join result code :",resultCode)
        
    }
    
    
    ///  对面超时还未接听
    private func detectWaitTimeout(){
        
        detectTimeoutDisposable = Observable<Int>.timer(.seconds(0), period: .seconds(1), scheduler: MainScheduler.instance)
                .take(waitTimeoutSeconds)
                .subscribe(onCompleted: {[weak self] in
                    print("#98013 等待超时",Date())
                    self?.leave(isOvertime: true)
                })
        
    }
    
    fileprivate func destroyTimer(){
        
//        NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(WaitingTimeoutAction), object: nil)
        
        timer?.invalidate()
        timer = nil

        detectTimeoutDisposable?.dispose()
        
        engagement_entiy?.totalSeconds = 0
        
        
        delegate?.engagementCurrentSeconds(seconds:  -1)
    }
    
    fileprivate func startTimer(){
        
        timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(chatSecondsLoop), userInfo: nil, repeats: true)
    }
    
    
    /// 每秒处理
    @objc fileprivate  func chatSecondsLoop(){
        
        
        
        if Defaults[.isPanda] == false{
            
            updateEngagementLogLoop()
            
            if displayIncomeControl{
                increaseIncomeDisplayLoop()
            }else{
                consumeCoinDisplayLoop()
            }
        }
        
        engagement_entiy?.totalSeconds += 1
        
        delegate?.engagementCurrentSeconds(seconds: engagement_entiy?.totalSeconds ?? 0)
        
    }
    
    func consumeCoinDisplayLoop(){
        
        
        guard let entity = engagement_entiy else { return }
        
        
        if entity.impressionSeconds > 0{
            
            engagement_entiy?.impressionSeconds -= 1
            
            delegate?.engagementMyCurrentImpression(currentSeconds: entity.impressionSeconds, haveState: entity.haveImpression)
            
            return
            
        }else if entity.freeTalkSeconds > 0{
            
            delegate?.engagementMyCurrentImpression(currentSeconds: 0, haveState: entity.haveImpression)
            
            self.delegate?.engagementMyCurrentFreeSeconds(seconds: engagement_entiy?.freeTalkSeconds ?? 0)
            
            engagement_entiy?.freeTalkSeconds -= 1
            
            return
            
        }
        
        if entity.totalSeconds < 59{
            delegate?.engagementMyCurrentImpression(currentSeconds: 0, haveState: entity.haveImpression)
        }
        
        
        
        self.delegate?.engagementMyCurrentFreeSeconds(seconds: 0)
        
        ST_BTUserInfoManager.shared.modify_consume_coin(offsetValue: entity.channelPrice)
        
        //            弹出提示 甜心币充值
        let currentSweetCoin = ST_BTUserInfoManager.shared.current_account_info?.userinfo?.sweet_coin ?? 0
        
        let requireCoin = ST_TIANEngagementConst.default.rechargeSeconds.float *  entity.channelPrice
        //            print("当前币:",currentSweetCoin,"----充值需要:",requireCoin,"--对面单价：",herCoinPerSecond)
        
        if currentSweetCoin < requireCoin && !entity.firstToastRecharge && !isSuspended {
            
            self.engagement_entiy?.firstToastRecharge = true
            
            let alert = ST_CallCountDownAlertController()
            
            alert.confirm_closure = {
                
                //TIANPayManager.shared.source = entity.chatType == .voice ? .语音冲币 : .视频冲币
                
                ST_RechargeViewController.toast()
            }
            
            alert.overCurrentContext = true
            
            alert.over_current_context_alpha = "0.4"
            
            GlobalPresent(toController: alert)
            
            return
        }
        
        //            没币了 挂断
        if currentSweetCoin < 2{
            
            if coinAlert == nil && !isSuspended{
                
                let alert = BTVerticalAlertViewController.createRequireRechargeAlert()
                
                alert.confirm_closure = {
                    
                    //TIANPayManager.shared.source = entity.chatType == .voice ? .语音冲币 : .视频冲币
                    
                    ST_RechargeViewController.toast()
                }
                
                GlobalPresent(toController: alert)
                
                self.coinAlert = alert
            }
            
            print("[strange bug]  没币了")
            
            self.leave()
            return
        }
        
        
        
        
    }
    
    func increaseIncomeDisplayLoop(){
        
        guard let entity = engagement_entiy else { return }
        
        if entity.freeTalkSeconds > 0 || entity.impressionSeconds > 0{
            
            delegate?.engagementIncrease(value: .free(seconds: entity.freeTalkSeconds + entity.impressionSeconds))
            
            if entity.impressionSeconds > 0{
                engagement_entiy?.impressionSeconds -= 1
            }else{
                engagement_entiy?.freeTalkSeconds -= 1
            }
            
            
        }else{
            
            engagement_entiy?.currentIncome += entity.channelPrice / 10.0
            
            ST_BTUserInfoManager.shared.increase_income(value: (entity.channelPrice/10.0).double, msgSendDate: Date())
            
            delegate?.engagementIncrease(value: .reducingValue(integral: engagement_entiy?.currentIncome ?? 0))
            
        }
        
    }
    
    
    
    
    fileprivate func updateEngagementLogLoop(){
        
        guard let entity = engagement_entiy,let myAccid = ST_BTUserInfoManager.shared.current_account_info?.accid  else { return }
        
        
        if engagementLog == nil {
            
            let log  = ST_EngagementCentLog()
            
            log.myId = myAccid
            
            log.herId = entity.sessionId
            
            
            
            log.sped_id = entity.spentId
            
            
            try! realm.write({
                realm.add(log)
            })
            
            engagementLog = log
            
        }else{
            
            try! realm.write({
                self.engagementLog?.endDate = Date()
            })
        }
        
    }
    
}

extension ST_TIANEngagementManager{
    
    
    
    fileprivate func playGoodsHandle(sessionID:String,isReceived:Bool = false,goods:ST_BTIMGiftMessageModel){
        
        if isSuspended{
            return
        }
        
        
        if goods.type == .gift{
            
            ST_GiftAnimationViewController.browserGift(imageUrl: goods.imageUrl, svgaUrl: goods.svgaUrl)
            
            
            return
        }else if goods.type == .sweetGuard{
            
            let animateVC = MemberGoodsAnimationViewController()
            
            animateVC.overCurrentContext = true
            
            animateVC.over_current_context_alpha = "0.4"
            
            if isReceived{
                
                animateVC.param = (ST_BTUserInfoManager.shared.current_account_info?.userinfo?.avatar ?? "",supplementUrl:goods.imageUrl)
            }else{
                
                
                
                animateVC.param = (engagement_entiy?.oppositeAvatar ?? "",supplementUrl:goods.imageUrl)
            }
            
            
            
            GlobalPresent(toController: animateVC, animated: false)
            
            return
        }
    }
    
    
    
    fileprivate func pushLogAction(){
        
        guard let entity = engagement_entiy ,entity.totalSeconds > 0 else{ return }
        
        NotificationCenter.default.post(name: ST_LiveBeautyWidget.delete_live_queue_notification, object: nil, userInfo: ["accid":entity.sessionId])
        
        let price = entity.channelPrice
        
        
        JVrequest(PH.chatLogApi,parameters: ["target_accid":entity.sessionId,"type":entity.chatType.rawValue,"connect_time":entity.totalSeconds,"price":price]) { (json) in
            
            print("发送日志成功:",json)
            
        } failure: { (code, err) in
            
            print("发送日志失败code:",code,"--error:",err)
        }
        
        
        
        
    }
    
    
    
    
}


extension ST_TIANEngagementManager{
    
    
    fileprivate func setup_notifications() {
        // Get the default notification center instance.
        let nc = NotificationCenter.default
        
        nc.addObserver(self,
                       selector: #selector(handle_interruption),
                       name: AVAudioSession.interruptionNotification,
                       object: nil)
        
        
        nc.addObserver(self, selector: #selector(received_gift(notification:)), name: Notification.Name.received_income_gift, object: nil)
        
        
        nc.addObserver(self, selector: #selector(received_warning(notification:)), name: NSNotification.Name.engagement_forbidden, object: nil)
        
    }
    
    /// 网易安全通
    private func push_talking_log(end:Bool = false){
        
        guard let entity = engagement_entiy else { return  }
        
        TIANSession(requestUrl: end ? PH.pushTalkingLogEndV2Api : PH.pushTalkingLogV2Api, parameters: ["channel_name":entity.channelId]).wrap_response_data().retry(maxAttempts: ST_SwiftConst.shared.dateLogTryTime, delay: 1).subscribe { _ in
            
            print(" TIANSession  通话中上报 success")
            
        } onError: { e in
            
            print(" TIANSession  通话中上报 ",e)
            
//            self.leave()
            
        }.disposed(by: rx.disposeBag)
        
    }
    
    ///  涉黄警告
    @objc func received_warning(notification: Notification) {
        
        let json = JSON(notification.userInfo ?? "")
        
        print("$yellow --1--",json)
        
        
//      ST_TIANEngagementManager 类 entity.currentChannel 改为 entity.channelId
        guard let entity = engagement_entiy, entity.channelId == json["channel"].stringValue else { return  }
        
        
        print("$yellow --2--")
        //        if json["channel"].stringValue != self.currentChannel  { return  }
        
        main_thread_execute {
            
            self.engagement_entiy?.currentChannelWarningTimes += 1
            
            print("$yellow --3--",self.engagement_entiy?.currentChannelWarningTimes ?? 90000)
            
            if entity.currentChannelWarningTimes > 3{
                
                if !self.isSuspended{
                    self.delegate?.engagementAlert(text: "出现违规，通话强制中断！")
                }
                
                
                self.leave()
                
                JVrequest(PH.shumeiSendMsgInformApi) { (json) in
                    
                    ST_BTUserInfoManager.shared.query_forbid_status()
                    
                } failure: { (code, err) in
                    
                }
                
                
            }else{
                
                if self.isSuspended{
                    return
                }
                
                
                let vc = BTVerticalAlertViewController.engagementWarningAlert(title: json["title"].stringValue, content: json["content"].stringValue)
                
                GlobalPresent(toController: vc)
                
            }
        }
        
        
        
    }
    
    @objc func received_gift(notification: Notification) {
        
        
        
        
        guard let entity = engagement_entiy,let msg = notification.userInfo?["msg"] as? ST_DTChatMessage ,let goods = msg.goods , msg.chatID == entity.sessionId  else { return  }
        
        
        let str = goods.title + "，\(Defaults[.PandaStr])+" + String(format: "%.2f", msg.tail.income)
        
        delegate?.engagementReceivedGift(str: str)
        
        playGoodsHandle(sessionID: msg.chatID, isReceived: true, goods: goods)
    }
    
    @objc func handle_interruption(notification: Notification) {
        
        
        print(" 麦克风 被打断 ---")
        
        self.leave()
        
        print("[strange bug] hung_up_action handle_interruption")
    }
    
    
    
    func push_gift_controller(){
        
        
        guard let entity = engagement_entiy else { return  }
        
        let giftAlert = ST_GiftViewController()
        
        giftAlert.overCurrentContext = true
        
        giftAlert.over_current_context_alpha = "0.4"
        
        giftAlert.userId = entity.sessionId
        
        giftAlert.displayToast = false
        
        giftAlert.goods_presented =  {[weak self] goods in
            
            let str = "送了你1个[" + goods.giftName + "]，亲密度+" + goods.intimacy.string
            
            self?.delegate?.engagementReceivedGift(str: str)
            
            self?.replied_all_income_message()
            
            if !goods.isBlindBox {
                self?.playGoodsHandle(sessionID: entity.sessionId, goods: goods)
            }
        }
        if let user = BINP.fetch_nickname_with_avatar(userId: entity.sessionId){
            
            giftAlert.avatar = user.avatar
        }
        
        
        GlobalPresent(toController: giftAlert)
        
    }
    
    /// 更改 礼物 小脚标，已读 收益
    fileprivate func replied_all_income_message(){
        
        guard let entity = engagement_entiy, let list = NIMSDK.shared().conversationManager.messages(in: NIMSession.init(entity.sessionId, type: NIMSessionType.P2P), message: nil, limit: 20) else { return  }
        
        let array = list.map({ST_DTChatMessage.analysis(message: $0)}).compactMap({$0})
        
        var repliedUpdateSet = Set<String>()
        
        for item in array{
            
            if item.tail.status == .willIncome{
                
                item.tail = ST_ChatMessageTailControlModel.init(income: item.tail.income, sendDate: item.tail.date, replied: true)
                
                repliedUpdateSet.update(with: item.uuid)
            }
        }
        
        if repliedUpdateSet.count > 0{
            
            let oldSet = Set(Defaults[.repliedGoodsSet])
            
            let unionSet = oldSet.union(repliedUpdateSet)
            
            Defaults[.repliedGoodsSet] = Array(unionSet)
            
            Defaults.synchronize()
        }
        
        
    }
    
    
    /// 挂断历史记录
    func send_hung_up_chat_history(){
        
        guard let entity = engagement_entiy,entity.targetRefuseMe == false else { return  }
        
        if ["接受邀请","邀请聊天"].contains(entity.fromPath) {
            
            let toSession = entity.sessionId
            
            //            if entity.pushPathStr == "接受邀请",let id = remoteJSON?["accid"].string {
            //
            //                toSession = id
            //            }
            
            if entity.totalSeconds > 0{
                
                print("【通话记录】- 结束通话")
                
                
                ST_DTChatFeed.shared.sendCallRecord(sessionId: toSession, agoraType: entity.chatType.rawValue, recordtype: ST_TIANRecordType.normalChat, time: entity.totalSeconds.float)
                
                
            }else{
                
                print("【通话记录】-自己取消")
                
                ST_DTChatFeed.shared.sendCallRecord(sessionId: toSession, agoraType: entity.chatType.rawValue, recordtype: ST_TIANRecordType.cancel, time: entity.totalSeconds.float)
            }
        }else if entity.fromPath.contains("匹配加入") && entity.totalSeconds > 0 {
            
            
            ST_DTChatFeed.shared.sendCallRecord(sessionId: entity.sessionId, agoraType: entity.chatType.rawValue, recordtype: ST_TIANRecordType.normalChat, time: entity.totalSeconds.float)
            
        }
    }
    
}


extension ST_TIANEngagementManager{
    
    
    func destroy(){
        
        // 上报数据问题
        
        DispatchQueue.global().async {
            
            print("#98013 界面释放问题 语言视频聊天")
            
            NEBeautyManager.shared().destroyNEBeauty()
            
            /// RS 销毁时机问题，可能是频道未退出完，NERtcEngine销毁了，导致频道无法退出，下次加入失败
            /// RS 测试为异步会导致未知问题，先修改成同步调用
//            print(NERtcEngine.destroy())
            
            DispatchQueue.main.async {
                
                print("#98013 界面释放问题 DispatchQueue.main")
                
                self.engagement_entiy = nil
                
                self.isSuspended = false
                
                ///回到之前的状态
                ST_BTUserInfoManager.shared.revert_last_status()
                
                ST_MediaChatDispatcher.shared.stop_waiting_voice()
                
            }
            
        }
        
        /// RS 测试为异步会导致未知问题，先修改成同步调用
        NERtcEngine.destroy()
        
        NotificationCenter.default.post(name: Notification.Name.sort_my_peculiarity, object: nil)
        
    }
    
    
    @objc  func hung_up_action(){
        leave()
    }
    
    func leave(isOvertime:Bool = false){
        /// RS 离开时清除muteRaw 的记录值
        muteRaw.removeAll()
        
        switch channelStatusBehavior.value {
        case .left:
//            outputSubject.onNext(.statusDidChanged(.leave))
            self.currentEngagementStatus = .hungUp
            print("#98013 【leave】 自己不在频道只是 UI 刷新")
        case .entered:
            print("#98013 【leave】 自己还在频道 call leaveChannel ,delegate 应该被调用")
            agoraKit.leaveChannel()
        case .prepare:
            
            print("#98013 【leave】自己还在prepare ")
            break
        }
        
        // 不是超时 ， 调佣 取消接口
        guard let entity = engagement_entiy,isOvertime  else{ return }
        
        ST_MediaChatDispatcher.shared.cancel_invite_chat(sessionId: entity.sessionId, isVideo:  entity.chatType == .video)
        
    }
    
    
    /// 视频通话，切换预览大小窗
    func swopVideoPreview(isPreviewBig:Bool){
        
        guard let entity = engagement_entiy,let remoteId = entity.remoteUserId else {
            return
        }
        
        
        
        
//        var remoteCanvas:NTESDemoUserModel?
        
        
        let localUserModel = NTESDemoUserModel()
        
        let remoteModel = NTESDemoUserModel()
        remoteModel.uid = remoteId
        
        localUserModel.renderContainer = isPreviewBig ? self.bigVideoViews : self.smallVideoViews
        
        remoteModel.renderContainer = !isPreviewBig ? self.bigVideoViews : self.smallVideoViews
       
        NERtcEngine.shared().setupLocalVideoCanvas(localUserModel.setupCanvas())
        
        NERtcEngine.shared().setupRemoteVideoCanvas(remoteModel.setupCanvas(), forUserID: remoteId)
        
    }
    
    func startEngine(engineParam:ST_TIANEngagementEntiy)->UIViewController{
        
        if engagement_entiy != nil {
            print("#ST_TIANEngagementManager engagement_entiy != nil")
        }
        
        
        self.currentEngagementStatus = .normal
        
        self.engagement_entiy = engineParam
        
        initializeAgoraEngine()
        
        switch engineParam.chatType {
        case .video:
            
            
            
            let videoController = ST_TIANVideoEngagementController()
            
            videoController.modalPresentationStyle = .overCurrentContext
            
            self.delegate = videoController
            
            GlobalPresent(toController: videoController, animated: false) {
                
                self.setupAgoraVideo()
                
                self.joinChannel()
                
            }
            
            return videoController
        case .voice:
            
            let voiceController = ST_TIANVoiceEngagementController()
            
            voiceController.modalPresentationStyle = .overCurrentContext
            
            voiceController.over_current_context_alpha = "0.4"
            
            self.delegate = voiceController
            
            GlobalPresent(toController: voiceController, animated: false) {
                
                self.setupAgoraVoice()
                
                self.joinChannel()
                
            }
            
            return voiceController
        }
    }
    
    
}

//    MARK: - Agora Delegate
extension ST_TIANEngagementManager : NERtcEngineDelegateEx{
    
    
    public func onNERtcEngineDidError(_ errCode: NERtcError) {
        
        //_forwardToDelegate?.onNERtcEngineDidError(errCode)
        
    }
    
    public func onNERtcEngineUserDidJoin(withUserID userID: UInt64, userName: String) {
         
        
        print("#98013 onNERtcEngineUserDidJoin")
        
        remoteUserId = userID
        currentEngagementStatus = .talking
        detectTimeoutDisposable?.dispose()
        
    }
    
    
    public func onNERtcEngineUserVideoDidStart(withUserID userID: UInt64, videoProfile profile: NERtcVideoProfileType) {
       
        
        print("#98013 onNERtcEngineUserVideoDidStart")
        
        if engagement_entiy?.remoteCanvas?.subscribedVideo == true{
            return
        }

        engagement_entiy?.remoteCanvas?.subscribedVideo = true

        engagement_entiy?.remoteUserId = userID
        
        agoraKit.subscribeRemoteVideo(true, forUserID: userID, streamType: .high)
        
        print("#98013 subscribeRemoteVideo")
        
        // RS 时机问题，调用swopVideoPreview 时， remoteUserId 为空
        ST_TIANEngagementManager.defaultManager.swopVideoPreview(isPreviewBig: true)
        
    }
    
    public func onNERtcEngineUserVideoDidStop(_ userID: UInt64) {
      
    }
    
    public func onNERtcEngineUserDidLeave(withUserID userID: UInt64, reason: NERtcSessionLeaveReason) {
        
        print("#98013 onNERtcEngineUserDidLeave 对面")
        
        leave()
        
        delegate?.engagementOtherPartyHangsUp()
      
    }
    
    public func onNERtcEngineDidLeaveChannel(withResult result: NERtcError) {
        
        
        print("#98013 onNERtcEngineDidLeaveChannel [ME]")
        
        channelStatusBehavior.accept(.left)
        someoneLeft()
        
        /// RS 云信不建议回调调用
//        NERtcEngine.destroy()

    }
    
    public func onNERtcEngineDidDisconnect(withReason reason: NERtcError) {
        
        channelStatusBehavior.accept(.left)
        
        someoneLeft()
        
        
        print("#98013 onNERtcEngineDidDisconnect [ME]")
        
        /// RS 云信不建议回调调用
//        NERtcEngine.destroy()
    }
    
    func onNERtcEngineVideoFrameCaptured(_ bufferRef: CVPixelBuffer, rotation: NERtcVideoRotationType) {
       
        
    }
    
    
    func onRemoteAudioVolumeIndication(_ speakers: [NERtcAudioVolumeInfo]?, totalVolume: Int32) {
        
        
        speakers?.forEach({ info in
            
            if info.volume < 3{
                
                
                if var time = muteRaw[info.uid]{
                    time += 1
                    muteRaw.updateValue(time, forKey: info.uid)
                    
                    print("#muteRaw 没有声音 time=",time)
                    
                    if time > muteWaitingTime {
                        leave()
                    }
                    
                }else{
                    muteRaw.updateValue(1, forKey: info.uid)
                    
                    print("#muteRaw 没有声音 new time")
                }
//                own.outputSubject.onNext(.doubtStatus(.display(fromMe: false)))
                delegate?.engagementDoubtLayout(isMe: false)
                
            }else{
                
                print("#muteRaw 有声音了 清除上次内容")
//                own.outputSubject.onNext(.doubtStatus(.hidden))
                
                delegate?.engagementHiddenDoubt()
                
                muteRaw.removeValue(forKey: info.uid)
            }
            
            
        })
        
    }
    
    
    private func someoneLeft(){
        
        currentEngagementStatus = .hungUp
        
        timerDisposable?.dispose()
        
    }
    
}
